Skip to content

fix(v3): Phase 4 cleanup — 6 Codex-flagged bugs (v0.9)#76

Open
mbreiser wants to merge 1 commit into
mainfrom
cleanup/phase4-bugs
Open

fix(v3): Phase 4 cleanup — 6 Codex-flagged bugs (v0.9)#76
mbreiser wants to merge 1 commit into
mainfrom
cleanup/phase4-bugs

Conversation

@mbreiser
Copy link
Copy Markdown
Contributor

Summary

Six Codex-flagged bugs in landed Phase 4 work, all isolated to already-merged code, all additive in spirit. Per the Round 2 handoff §1 / §3 Tier 1.

  • A1 (experiment_designer_v3.html:1809): #sequenceList drag/drop listeners moved out of renderSequence() into one-time startup wiring. Previously re-attached every render → after N renders a single drop fired N handlers → N duplicate refs + N undo entries.
  • A2 (experiment_designer_v3.html:1476): onMoveSequenceEntry and onInsertSequenceRefFromLib walk selection.index across the full displacement, not just the moved entry. Library drag-drop no longer steals selection focus.
  • A3 (experiment_designer_v3.html:3187): Timeline ruler tick positions computed piecewise via new rulerXForRealTime() walking the layout array. Flat pxPerSec drifted once any short step clamped to the 60/40px minimum.
  • A4 (experiment_designer_v3.html:1544, js/protocol-yaml-v3.js:1154): isConvertibleBlock rejects entries with non-empty _unknownKeys. Block→ref convert was silently dropping forward-compat fields, undermining the Tier 1 unknown-passthrough guarantee.
  • A5 (js/protocol-yaml-v3.js:1022): _buildSequenceEntry mirrors the parser's positive-integer repetitions validation. Closed a doc/JS-mirror divergence path that D4/paste-import would hit.
  • A6 (experiment_designer_v3.html:2611): onMoveCommand defensively early-returns on no-op / out-of-bounds.

Tests: 375/375 (was 369). Added 6 builder-side validation tests to Suite 10b.

Footer bumped to v0.9 | 2026-05-27 19:54 ET.

Test plan

  • npm test — arena 10/10, v2 137/137, v3 228/228 (375 total)
  • A1 verified: 30 forced re-renders + 1 simulated library drop adds exactly 1 entry (would have added 30 with the bug)
  • A4 verified: Right-click on v3_future_keys.yaml block shows error listing forward-compat keys: retry_on_fail, abort_if
  • A3 verified: v3_multi_block.yaml (mixed durations exercising 60px clamping) renders "1m" tick at x=2447 of 3516-px ruler — piecewise positioning works
  • Manual: drag a sequence entry onto itself (no-op) — confirm undo stack unchanged
  • Manual: with a ref at index 5 selected, drag a library row to index 1 — confirm inspector still shows the originally-selected ref at its new index (6)
  • Manual: visually compare ruler "1m" placement before/after on a fixture with clamped short steps

Notes

This unblocks Phase 5 (Variables UX), which lands as a follow-up PR.

🤖 Generated with Claude Code

…ler ticks, convert _unknownKeys (v0.9)

Six Codex-flagged bugs in landed Phase 4 work:

- A1: #sequenceList drag/drop listeners moved to one-time startup wiring.
  Previously re-attached on every renderSequence(); a single drop after N
  renders fired N handlers, inserting N duplicate refs and pushing N undo
  entries. Surfaced within a normal editing session.
- A2: onMoveSequenceEntry and onInsertSequenceRefFromLib now walk
  selection.index across the full displacement, not just the moved entry.
  Library drag-drop no longer steals selection focus — it shifts the
  existing selection through the insert (matches the +Add Ref button's
  intent of selecting the new entry only for explicit button clicks).
- A3: Timeline ruler tick positions are computed piecewise by walking the
  layout array (rulerXForRealTime), so ticks stay aligned with clamped
  step widths. Flat pxPerSec drifted as soon as any short step clamped to
  the 60px / 40px minimum.
- A4: isConvertibleBlock rejects entries with non-empty _unknownKeys.
  Block→ref convert was silently dropping forward-compat fields like
  retry_on_fail, undermining the Tier 1 unknown-passthrough guarantee.
  The user-facing error message now enumerates every blocker including
  forward-compat keys.
- A5: _buildSequenceEntry mirrors the parser's positive-integer
  repetitions validation. Closed a doc/JS-mirror divergence path that
  D4/paste-import would hit (entry.repetitions = 0 → YAML '0' but mirror
  = 1 via `|| 1` default).
- A6: onMoveCommand defensively early-returns on no-op / out-of-bounds,
  matching the onMoveSequenceEntry pattern. Avoids pushUndo pollution.

Tests: 375/375 (was 369). Added 6 new builder-side validation cases to
Suite 10b for A5.

Verified in browser:
- A1: 30 forced re-renders + 1 simulated library drop adds exactly 1 entry.
- A4: Right-click on future_keys block shows full error listing all
  blockers including `forward-compat keys: retry_on_fail, abort_if`.
- A3: Multi_block fixture (mixed durations exercising 60px clamping)
  shows "1m" tick at x=2447 of a 3516-px ruler — piecewise positioning.

Footer bumped to v0.9 | 2026-05-27 19:54 ET.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant